package com.winit.openapi.oauth.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.message.types.ResponseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONObject;
import com.winit.common.spi.SPIException;
import com.winit.common.spi.command.GetByKeyCommand;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.controller.BaseController;
import com.winit.openapi.exception.ApiBizException;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.oauth.manager.APIClientManager;
import com.winit.openapi.oauth.manager.UserAuthorizationManager;
import com.winit.openapi.oauth.util.OAuth2SecurityUtil;
import com.winit.openapi.oauth.vo.APIClientVo;
import com.winit.openapi.oauth.vo.UserAuthorizationVo;
import com.winit.openapi.util.APISysConfigUtil;
import com.winit.openapi.util.HttpUtil;
import com.winit.openapi.util.RedisUtil;
import com.winit.openapi.util.ValidateUtil;
import com.winit.ums.spi.UmsUserService;
import com.winit.ums.spi.user.command.QueryTokenCommand;
import com.winit.ums.spi.vo.user.UserVO;

/**
 * OAuth2.0授权功能模块实现
 * 
 * @version <pre>
 * Author	Version		Date		Changes
 * minghao.deng 	1.0  		2017年10月16日 	Created
 *
 * </pre>
 * @since 1.
 */
@Controller
@RequestMapping(value = "/oauth2")
public class UserAuthorizationController extends BaseController {

    private static final Logger      logger            = LoggerFactory.getLogger(UserAuthorizationController.class);

    private static final String      OAUTH_USER_PREFIX = "OAuth_code_";

    @Resource
    private UmsUserService           umsUserService;

    @Resource
    private APIClientManager         apiClientManager;

    @Resource
    private UserAuthorizationManager userAuthorizationManager;

    @Resource
    private APISysConfigUtil         apiSysConfigUtil;

    @RequestMapping(value = "/authorize", method = RequestMethod.GET)
    public ModelAndView login(HttpServletRequest request) throws ServletException, IOException {

        ModelAndView mav = new ModelAndView();

        String sourceUrl = request.getHeader("Referer");
        mav.addObject("client_url", sourceUrl);
        String clientId = request.getParameter("client_id");
        if (StringUtils.isBlank(clientId)) {
            mav.addObject("error_description", "client_id不能为空");
            mav.addObject("error", OAuthError.TokenResponse.INVALID_REQUEST);
            mav.setViewName("failed.jsp");
            return mav;
        }

        APIClientVo client = apiClientManager.selectByClientKey(clientId);
        if (null == client) {
            mav.addObject("error_description", "应用不存在或者无效");
            mav.addObject("error", OAuthError.TokenResponse.INVALID_REQUEST);
            mav.setViewName("failed.jsp");
            return mav;
        }

        request.setAttribute("client_name", client.getClientName());

        mav.setViewName("authorization.jsp");
        mav.addObject("client_name", client.getClientName());
        mav.addObject("client_logo", client.getLogoImageUri());
        mav.addObject("client_id", clientId);
        mav.addObject("state", request.getParameter("state"));
        mav.addObject("response_type", request.getParameter("response_type"));
        mav.addObject("redirect_uri", request.getParameter("redirect_uri"));

        // response.sendRedirect("index.jsp");

        return mav;

    }

    /**
     * 隐式授权， 1.直接返回用户在卖家网站登录的token 2.后台生成access_token保存用于记录本次授权
     * 
     * @param request
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping(value = "/implicitGrant")
    public ModelAndView implicitGrant(HttpServletRequest request) throws ServletException, IOException {

        ModelAndView mav = new ModelAndView("failed.jsp");
        String userName = request.getParameter(OAuth.OAUTH_USERNAME);
        String password = request.getParameter(OAuth.OAUTH_PASSWORD);
        String redirectUri = request.getParameter(OAuth.OAUTH_REDIRECT_URI);
        String responseType = request.getParameter(OAuth.OAUTH_RESPONSE_TYPE);
        String clientId = request.getParameter(OAuth.OAUTH_CLIENT_ID);
        String clientUrl = request.getParameter("client_url");

        if (StringUtils.isBlank(clientUrl)) {
            clientUrl = request.getHeader("Referer");
        }

        UserVO userVo = null;
        APIClientVo client = null;
        String accessToken = null;
        String refreshToken = null;
        String accsessTokenExpireTime = null;
        String token = null;

        try {
            // 构建OAuth请求
            if (StringUtils.isBlank(clientId)) {
                mav.addObject("client_url", clientUrl);
                mav.addObject("error_description", "无效的客户端Id");
                mav.addObject("error", OAuthError.TokenResponse.INVALID_CLIENT);
                return mav;
            }
            // 校验客户端Id是否正确
            client = apiClientManager.selectByClientKey(clientId);
            if (null == client) {
                mav.addObject("client_url", clientUrl);
                mav.addObject("error_description", "客户端不存在或未审核");
                mav.addObject("error", OAuthError.TokenResponse.UNAUTHORIZED_CLIENT);
                return mav;
            }
            if ("N".equals(client.getIsDefaultUrl())) {
                // 校验跳转uri是否与注册时一致，防止篡改
                if (!client.getRedirectUrl().equals(redirectUri)) {
                    mav.addObject("client_url", clientUrl);
                    mav.addObject("client_name", client.getClientName());
                    mav.addObject("error_description", "回调RUL与注册时不符!");
                    mav.addObject("error", OAuthError.TokenResponse.UNAUTHORIZED_CLIENT);
                    return mav;
                }
            }
            // 隐式授权response_type=token
            if (!responseType.equals(ResponseType.TOKEN.toString())) {
                mav.addObject("client_url", clientUrl);
                mav.addObject("client_name", client.getClientName());
                mav.addObject("error_description", "无效的响应类型");
                mav.addObject("error", OAuthError.CodeResponse.UNSUPPORTED_RESPONSE_TYPE);
                return mav;
            }
            QueryTokenCommand userCommand = new QueryTokenCommand();
            userCommand.setUserName(userName);
            userCommand.setPassword(password);
            token = umsUserService.getToken(userCommand);
            if (StringUtils.isBlank(token)) {
                mav.addObject("error_description", "无效的用户名");
                mav.addObject("client_url", clientUrl);
                mav.addObject("error", OAuthError.TokenResponse.INVALID_REQUEST);
                return mav;
            }

            String para = "access_token=" + token + "&username=" + userName;
            // 有WEB服务的直接调WEB接口，否则直接回调URL
            if ("N".equals(client.getIsDefaultUrl())) {
                List<String> list = Arrays.asList(".com", ".cn", ".net", ".org", ".gov", ".edu");
                boolean isPublic = false;
                for (String string : list) {
                    if (client.getRedirectUrl().endsWith(string)) {
                        isPublic = true;
                        break;

                    }
                }
                if (isPublic) {
                    mav.setViewName("redirect:" + redirectUri);
                    mav.addObject("access_token", token);
                    mav.addObject("username", userName);
                } else {

                    int code = HttpUtil.doGet(client.getRedirectUrl(), para);
                    if (200 == code) {
                        mav.addObject("access_token", token);
                        mav.addObject("username", userName);
                        mav.addObject("client_name", client.getClientName());
                        mav.addObject("client_url", clientUrl);
                        mav.setViewName("success.jsp");

                    }
                }
            } else {
                mav.setViewName("success.jsp");
                mav.addObject("isDefaultURL", client.getIsDefaultUrl());
                mav.addObject("client_name", client.getClientName());
                mav.addObject("client_url", clientUrl);
                mav.addObject("access_token", token);
                // mav.addObject("username", URLEncoder.encode(userName,
                // "utf-8"));
                mav.addObject("username", userName);
            }

            GetByKeyCommand<String> command = new GetByKeyCommand<String>();
            command.setSearchKey(userName);
            userVo = umsUserService.queryByUsername(command);
            accessToken = OAuth2SecurityUtil.generateAcceccToken();
            refreshToken = OAuth2SecurityUtil.generateAcceccToken();
            accsessTokenExpireTime = apiSysConfigUtil.getConfigValueByKey("API_OAUTH2_ACCESS_TOKEN_EXPIRED_TIME");

        } catch (SPIException e) {
            mav.addObject("client_url", clientUrl);
            mav.addObject("client_name", client == null ? StringUtils.EMPTY : client.getClientName());
            mav.setViewName("failed.jsp");
            mav.addObject("error_description", "用户名或密码错误");
            mav.addObject("error", OAuthError.TokenResponse.INVALID_REQUEST);
            logger.error("获取临时code失败，" + e);
            return mav;
        } catch (IOException e) {
            mav.addObject("client_url", clientUrl);
            mav.addObject("client_name", client.getClientName());
            mav.setViewName("failed.jsp");
            mav.addObject("error_description", "发送回调请求失败,请检查URL是否有误");
            mav.addObject("error", OAuthError.CodeResponse.ACCESS_DENIED);
            logger.error("发送回调请求失败，" + e);
            return mav;
        } catch (Exception e) {
            mav.addObject("client_url", clientUrl);
            mav.addObject("client_name", client == null ? StringUtils.EMPTY : client.getClientName());
            mav.setViewName("failed.jsp");
            mav.addObject("error_description", "授权失败，请稍后再试");
            mav.addObject("error", OAuthError.CodeResponse.SERVER_ERROR);
            logger.error("授权失败，" + e);
            return mav;
        }

        int expireMonth = StringUtils.isBlank(accsessTokenExpireTime) ? 18 : Integer.valueOf(accsessTokenExpireTime);
        // 默认有效期是1年半18个月
        Calendar expireTime = Calendar.getInstance();
        expireTime.set(Calendar.MONTH, expireTime.get(Calendar.MONTH) + expireMonth);
        UserAuthorizationVo vo = new UserAuthorizationVo();
        vo.setUserId(userVo.getId());
        vo.setClientId(client.getId());
        vo.setAccessToken(accessToken);
        vo.setRefreshToken(refreshToken);
        vo.setExpireTime(expireTime.getTime());
        vo.setCreated(new Date());
        vo.setCreatedby(userName);
        vo.setUserName(userName);
        vo.setClientName(client.getClientName());
        userAuthorizationManager.insertOrUpdate(vo);

        return mav;

    }

    @RequestMapping(value = "/getCode")
    public ModelAndView getCode(HttpServletRequest request) throws ServletException, IOException {

        ModelAndView mav = new ModelAndView();
        String userName = request.getParameter(OAuth.OAUTH_USERNAME);
        String password = request.getParameter(OAuth.OAUTH_PASSWORD);
        String state = request.getParameter(OAuth.OAUTH_STATE);
        String redirectUri = request.getParameter(OAuth.OAUTH_REDIRECT_URI);

        QueryTokenCommand userCommand = new QueryTokenCommand();
        userCommand.setUserName(userName);
        userCommand.setPassword(password);
        String token = umsUserService.getToken(userCommand);
        if (StringUtils.isBlank(token)) {
            mav.addObject("error_description", "无效的用户名");
            mav.addObject("error", OAuthError.TokenResponse.INVALID_REQUEST);
            mav.setViewName("failed.jsp");
            // mav.setViewName("forward:/oauth2/authorizefailed");
            return mav;
        }
        // 获取OAuth客户端Id
        String clientId = null;
        String authCode = null;
        try {
            // 构建OAuth请求
            OAuthAuthzRequest oAuthzRequest = new OAuthAuthzRequest(request);
            clientId = oAuthzRequest.getClientId();
            if (StringUtils.isBlank(clientId)) {
                mav.addObject("error_description", "无效的客户端Id");
                mav.addObject("error", OAuthError.TokenResponse.INVALID_CLIENT);
                mav.setViewName("failed.jsp");
                // mav.setViewName("forward:/oauth2/authorizefailed");
                return mav;
            }
            // 校验客户端Id是否正确
            APIClientVo client = apiClientManager.selectByClientKey(clientId);
            if (null == client) {
                mav.addObject("error_description", "客户端不存在或未审核");
                mav.addObject("error", OAuthError.TokenResponse.UNAUTHORIZED_CLIENT);
                mav.setViewName("failed.jsp");
                return mav;
            }
            // 校验跳转uri是否与注册时一致，防止篡改
            if (!client.getRedirectUrl().equals(redirectUri)) {
                mav.addObject("error_description", "回调RUL与注册时不符!");
                mav.addObject("error", OAuthError.TokenResponse.UNAUTHORIZED_CLIENT);
                mav.setViewName("failed.jsp");
                return mav;
            }

            String responseType = oAuthzRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
            if (responseType.equals(ResponseType.CODE.toString())) {
                // 生成CODE
                authCode = OAuth2SecurityUtil.generateAuthCode();
            } else {
                mav.addObject("error_description", "无效的响应类型");
                mav.addObject("error", OAuthError.CodeResponse.UNSUPPORTED_RESPONSE_TYPE);
                mav.setViewName("failed.jsp");
                return mav;
            }
        } catch (OAuthSystemException e) {
            mav.addObject("error_description", "授权失败，请稍后再试");
            mav.addObject("error", OAuthError.CodeResponse.SERVER_ERROR);
            logger.error("获取临时code失败，" + e);
            mav.setViewName("failed.jsp");
            return mav;
        } catch (OAuthProblemException e) {
            mav.addObject("error_description", "授权失败，请稍后再试");
            mav.addObject("error", OAuthError.CodeResponse.SERVER_ERROR);
            logger.error("获取临时code失败，" + e);
            mav.setViewName("failed.jsp");
            return mav;
        }

        mav.addObject(OAuth.OAUTH_CODE, authCode);
        if (StringUtils.isNoneBlank(state)) {
            mav.addObject(OAuth.OAUTH_STATE, state);
        }
        mav.setViewName("redirect:" + redirectUri);
        // 缓存授权临时code,默认有效期2分钟
        String codeExpireTime = apiSysConfigUtil.getConfigValueByKey("API_OAUTH2_AUTHORIZATION_CODE_TIME_OUT");
        RedisUtil.put(OAUTH_USER_PREFIX + clientId + authCode,
            userName,
            StringUtils.isBlank(codeExpireTime) ? 60 * 2 : Integer.valueOf(codeExpireTime));

        return mav;

    }

    @RequestMapping(value = "/getAccessToken")
    @ResponseBody
    public ResponseEntity getAccessToken(HttpServletRequest request) {

        // 生成访问令牌
        OAuthResponse response = null;
        try {
            // 构建OAuth请求
            OAuthTokenRequest tokenRequest = new OAuthTokenRequest(request);
            // 获取OAuth客户端Id
            String clientId = tokenRequest.getClientId();
            String redirectUri = tokenRequest.getRedirectURI();
            String clientSecret = tokenRequest.getClientSecret();
            // 1.校验clientId的合法性
            if (StringUtils.isBlank(clientId)) {
                OAuthResponse oAuthResponse = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_CLIENT)
                    .setErrorDescription("无效的客户端Id")
                    .buildJSONMessage();
                return new ResponseEntity(oAuthResponse.getBody(),
                    HttpStatus.valueOf(oAuthResponse.getResponseStatus()));

            }
            // // 2.检查客户端安全KEY和秘钥
            if (!apiClientManager.checkLogin(clientId, clientSecret)) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
                    .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
                    .setErrorDescription("客户端Id或密匙有误")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            APIClientVo client = apiClientManager.selectByClientKey(clientId);
            // 校验跳转uri是否与注册时一致，防止篡改
            if (!client.getRedirectUrl().equals(redirectUri)) {
                response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
                    .setErrorDescription("客户端回调URL有误或与注册时不一致")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }

            String authCode = tokenRequest.getParam(OAuth.OAUTH_CODE);
            String key = OAUTH_USER_PREFIX + clientId + authCode;
            if (tokenRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())) {
                if (!RedisUtil.contains(key)) {
                    response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                        .setError(OAuthError.TokenResponse.INVALID_GRANT)
                        .setErrorDescription("授权码有误或者已经过期")
                        .buildJSONMessage();
                    return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
                }
            }
            String userName = RedisUtil.get(key);
            String accessToken = OAuth2SecurityUtil.generateAcceccToken();
            String refreshToken = OAuth2SecurityUtil.generateAcceccToken();
            GetByKeyCommand<String> userCommand = new GetByKeyCommand<String>();
            userCommand.setSearchKey(userName);
            UserVO userVo = umsUserService.queryByUsername(userCommand);
            if (null == userVo) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_REQUEST)
                    .setErrorDescription("用户未找到")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            String accsessTokenExpireTime = apiSysConfigUtil.getConfigValueByKey("API_OAUTH2_ACCESS_TOKEN_EXPIRED_TIME");
            int expireMonth = StringUtils.isBlank(accsessTokenExpireTime) ? 18 : Integer.valueOf(accsessTokenExpireTime);
            // 默认有效期是1年半18个月
            Calendar expireTime = Calendar.getInstance();
            expireTime.set(Calendar.MONTH, expireTime.get(Calendar.MONTH) + expireMonth);
            response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK)
                .setAccessToken(accessToken)
                .setRefreshToken(refreshToken)
                .setParam(OAuth.OAUTH_USERNAME, userName)
                .setExpiresIn(String.valueOf(expireTime))
                .buildJSONMessage();
            UserAuthorizationVo vo = new UserAuthorizationVo();
            vo.setUserId(userVo.getId());
            vo.setClientId(client.getId());
            vo.setAccessToken(accessToken);
            vo.setExpireTime(expireTime.getTime());
            vo.setCreated(new Date());
            vo.setCreatedby(userName);
            vo.setUserName(userName);
            vo.setClientName(client.getClientName());
            userAuthorizationManager.insertOrUpdate(vo);
            // 授权成功，从缓存中移除code
            RedisUtil.remove(OAUTH_USER_PREFIX + clientId + authCode);
        } catch (OAuthProblemException e) {
            logger.error("用户授权操作异常：" + e);
            return new ResponseEntity(e.getDescription(), HttpStatus.valueOf(e.getError()));
        } catch (Exception e) {
            logger.error("用户授权操作异常：" + e);
            return new ResponseEntity("用户授权失败，请稍后再试", HttpStatus.valueOf(HttpServletResponse.SC_BAD_REQUEST));
        }

        return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
    }

    /**
     * 用户刷新access_token
     * 
     * @param requestMsg
     * @return
     */
    @RequestMapping(value = "/refreshToken")
    @ResponseBody
    public ResponseEntity refreshToken(HttpServletRequest request) {

        // 生成访问令牌
        OAuthResponse response = null;
        try {
            // 构建OAuth请求
            OAuthTokenRequest tokenRequest = new OAuthTokenRequest(request);
            // 获取OAuth客户端Id
            String clientId = tokenRequest.getClientId();
            // String redirectUri = tokenRequest.getRedirectURI();
            String clientSecret = tokenRequest.getClientSecret();
            // 1.校验clientId的合法性
            if (StringUtils.isBlank(clientId)) {
                OAuthResponse oAuthResponse = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_CLIENT)
                    .setErrorDescription("无效的客户端Id")
                    .buildJSONMessage();
                return new ResponseEntity(oAuthResponse.getBody(),
                    HttpStatus.valueOf(oAuthResponse.getResponseStatus()));

            }
            // 2.检查客户端安全KEY和秘钥
            if (!apiClientManager.checkLogin(clientId, clientSecret)) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
                    .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
                    .setErrorDescription("客户端Id或密匙有误")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            APIClientVo client = apiClientManager.selectByClientKey(clientId);
            // 如果授权类型不是refresh_token
            if (!tokenRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.REFRESH_TOKEN.toString())) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_GRANT)
                    .setErrorDescription("无效的授权类型")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            // 验证用户
            String userName = tokenRequest.getUsername();
            GetByKeyCommand<String> userCommand = new GetByKeyCommand<String>();
            userCommand.setSearchKey(userName);
            UserVO userVo = umsUserService.queryByUsername(userCommand);
            if (null == userVo) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_REQUEST)
                    .setErrorDescription("用户未找到")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            // 校验refresh_token是否正确
            UserAuthorizationVo authVo = userAuthorizationManager.queryByClientAndUser(client.getId(), userVo.getId());
            if (null == authVo) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_REQUEST)
                    .setErrorDescription("用户授权信息不存在")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            String refreshTokenFromUser = tokenRequest.getRefreshToken();
            if (!authVo.getRefreshToken().equals(refreshTokenFromUser)) {
                response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_REQUEST)
                    .setErrorDescription("refresh_token不存在")
                    .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
            String accsessTokenExpireTime = apiSysConfigUtil.getConfigValueByKey("API_OAUTH2_ACCESS_TOKEN_EXPIRED_TIME");
            int expireMonth = StringUtils.isBlank(accsessTokenExpireTime) ? 18 : Integer.valueOf(accsessTokenExpireTime);
            // 默认有效期是1年半18个月
            Calendar expireTime = Calendar.getInstance();
            expireTime.set(Calendar.MONTH, expireTime.get(Calendar.MONTH) + expireMonth);
            String accessToken = OAuth2SecurityUtil.generateAcceccToken();
            String refreshToken = OAuth2SecurityUtil.generateAcceccToken();
            response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK)
                .setAccessToken(accessToken)
                .setRefreshToken(refreshToken)
                .setParam(OAuth.OAUTH_USERNAME, userName)
                .setExpiresIn(String.valueOf(expireTime))
                .buildJSONMessage();
            authVo.setAccessToken(accessToken);
            authVo.setRefreshToken(refreshToken);
            authVo.setExpireTime(expireTime.getTime());
            authVo.setUpdated(new Date());
            authVo.setCreatedby(userName);
            authVo.setUserName(userName);
            authVo.setClientName(client.getClientName());
            userAuthorizationManager.insertOrUpdate(authVo);
        } catch (OAuthProblemException e) {
            logger.error("用户刷新授权操作异常：" + e);
            return new ResponseEntity(e.getDescription(), HttpStatus.valueOf(e.getError()));
        } catch (Exception e) {
            logger.error("用户刷新授权操作异常：" + e);
            return new ResponseEntity("用户刷新授权失败，请稍后再试", HttpStatus.valueOf(HttpServletResponse.SC_BAD_REQUEST));
        }

        return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
    }

    /**
     * 用户取消应用绑定
     * 
     * @param requestMsg
     * @return
     */
    @RequestMapping(value = "/user/unbind")
    public String unbind(@ModelAttribute RequestMsg requestMsg) {

        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            try {
                JSONObject json = (JSONObject) obj;
                ValidateUtil.validNotNull(json, "clientId");
                ValidateUtil.validNotNull(json, "userName");
                String clientKey = json.getString("clientId");
                String userName = json.getString("userName");
                APIClientVo vo = apiClientManager.selectByClientKey(clientKey);
                if (null == vo) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR);
                }
                GetByKeyCommand<String> userCommand = new GetByKeyCommand<String>();
                userCommand.setSearchKey(userName);
                UserVO userVo = umsUserService.queryByUsername(userCommand);
                if (userVo == null) {
                    throw new ApiException(ErrorCode.USER_NOT_FOUND);
                }
                userAuthorizationManager.unbind(vo.getId(), userVo.getId());
            } catch (ApiBizException e) {
                logger.error("APIClientController->delete client :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_CLIENT_DELETE_ERROR);
            }

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }

        return SUCCESS;
    }

    /**
     * 用户取消应用绑定
     * 
     * @param requestMsg
     * @return
     */
    @RequestMapping(value = "/user/token/refresh")
    public String refreshToken(@ModelAttribute RequestMsg requestMsg) {

        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            UserAuthorizationVo authVo = null;
            String accessToken = null;
            String newRefreshToken = null;
            String accsessTokenExpireTime = null;
            String userName = null;
            try {
                JSONObject json = (JSONObject) obj;
                ValidateUtil.validNotNull(json, "clientId");
                ValidateUtil.validNotNull(json, "userName");
                ValidateUtil.validNotNull(json, "refreshToken");
                String clientKey = json.getString("clientId");
                userName = json.getString("userName");
                String refreshToken = json.getString("refreshToken");

                APIClientVo vo = apiClientManager.selectByClientKey(clientKey);
                if (null == vo) {
                    throw new ApiException(ErrorCode.OAUTH_CLIENT_NOT_EXISTS_ERROR);
                }
                GetByKeyCommand<String> userCommand = new GetByKeyCommand<String>();
                userCommand.setSearchKey(userName);
                UserVO userVo = umsUserService.queryByUsername(userCommand);
                if (userVo == null) {
                    throw new ApiException(ErrorCode.USER_NOT_FOUND);
                }
                authVo = userAuthorizationManager.queryByClientAndUser(vo.getId(), userVo.getId());
                if (null == authVo) {
                    throw new ApiException(ErrorCode.OAUTH_USER_AUTH_NOT_EXISTS_ERROR);
                }
                if (!authVo.getRefreshToken().equals(refreshToken)) {
                    throw new ApiException(ErrorCode.OAUTH_REFRESH_TOKEN_NOT_EXISTS_ERROR);
                }
                accessToken = OAuth2SecurityUtil.generateAcceccToken();
                newRefreshToken = OAuth2SecurityUtil.generateAcceccToken();
                userName = userVo.getUsername();
                accsessTokenExpireTime = apiSysConfigUtil.getConfigValueByKey("API_OAUTH2_ACCESS_TOKEN_EXPIRED_TIME");

            } catch (OAuthSystemException e) {
                logger.error("refreshToken->refresh token  :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_REFRESH_TOKEN_FAIL);

            } catch (ApiBizException e) {
                logger.error("refreshToken->refresh token  :error:{}", e);
                throw new ApiException(ErrorCode.OAUTH_REFRESH_TOKEN_FAIL);
            }

            int expireMonth = StringUtils.isBlank(accsessTokenExpireTime) ? 18 : Integer.valueOf(accsessTokenExpireTime);
            // 默认有效期是1年半18个月
            Calendar expireTime = Calendar.getInstance();
            expireTime.set(Calendar.MONTH, expireTime.get(Calendar.MONTH) + expireMonth);
            authVo.setAccessToken(accessToken);
            authVo.setRefreshToken(newRefreshToken);
            authVo.setExpireTime(expireTime.getTime());
            authVo.setUpdated(new Date());
            authVo.setUpdatedby(userName);
            userAuthorizationManager.insertOrUpdate(authVo);

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }

        return SUCCESS;
    }
}
